package org.proteored.miapeapi.xml.mzidentml;

import java.io.File;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;
import org.proteored.miapeapi.cv.Accession;
import org.proteored.miapeapi.cv.ControlVocabularyManager;
import org.proteored.miapeapi.cv.ControlVocabularyTerm;
import org.proteored.miapeapi.cv.ms.RetentionTime;
import org.proteored.miapeapi.exceptions.IllegalMiapeArgumentException;
import org.proteored.miapeapi.exceptions.MiapeDatabaseException;
import org.proteored.miapeapi.exceptions.MiapeSecurityException;
import org.proteored.miapeapi.experiment.model.sort.SystemCoreManager;
import org.proteored.miapeapi.interfaces.Contact;
import org.proteored.miapeapi.interfaces.MiapeDate;
import org.proteored.miapeapi.interfaces.Project;
import org.proteored.miapeapi.interfaces.Software;
import org.proteored.miapeapi.interfaces.User;
import org.proteored.miapeapi.interfaces.ms.MSContact;
import org.proteored.miapeapi.interfaces.ms.MiapeMSDocument;
import org.proteored.miapeapi.interfaces.msi.IdentifiedPeptide;
import org.proteored.miapeapi.interfaces.msi.IdentifiedProtein;
import org.proteored.miapeapi.interfaces.msi.IdentifiedProteinSet;
import org.proteored.miapeapi.interfaces.msi.InputData;
import org.proteored.miapeapi.interfaces.msi.InputDataSet;
import org.proteored.miapeapi.interfaces.msi.InputParameter;
import org.proteored.miapeapi.interfaces.msi.MSIAdditionalInformation;
import org.proteored.miapeapi.interfaces.msi.MiapeMSIDocument;
import org.proteored.miapeapi.interfaces.msi.PeptideScore;
import org.proteored.miapeapi.interfaces.msi.Validation;
import org.proteored.miapeapi.interfaces.persistence.PersistenceManager;
import org.proteored.miapeapi.interfaces.xml.MiapeXmlFile;
import org.proteored.miapeapi.interfaces.xml.XmlMiapeFactory;
import org.proteored.miapeapi.validation.ValidationReport;
import org.proteored.miapeapi.validation.msi.MiapeMSIValidator;
import org.proteored.miapeapi.xml.msi.MiapeMSIXmlFactory;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.AnalysisDataType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.AnalysisProtocolCollectionType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.DataCollectionType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.FuGEBioDataExternalDataType.FileFormat;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.FuGECollectionAuditCollectionType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.FuGECommonAuditContactType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.FuGECommonOntologyCvParamType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.FuGECommonOntologyParamType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.FuGECommonReferencesBibliographicReferenceType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.InputSpectraType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.InputSpectrumIdentificationsType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.PSIPIAnalysisProcessProteinAmbiguityGroupType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.PSIPIAnalysisProcessProteinDetectionHypothesisType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.PSIPIAnalysisProcessProteinDetectionListType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.PSIPIAnalysisProcessProteinDetectionProtocolType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.PSIPIAnalysisProcessProteinDetectionType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.PSIPIAnalysisSearchAnalysisSoftwareType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.PSIPIAnalysisSearchDBSequenceType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.PSIPIAnalysisSearchSearchDatabaseType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.PSIPIAnalysisSearchSourceFileType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.PSIPIAnalysisSearchSpectrumIdentificationItemType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.PSIPIAnalysisSearchSpectrumIdentificationListType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.PSIPIAnalysisSearchSpectrumIdentificationProtocolType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.PSIPIAnalysisSearchSpectrumIdentificationResultType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.PSIPIAnalysisSearchSpectrumIdentificationType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.PSIPIMainMzIdentMLType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.PSIPIPolypeptidePeptideType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.PSIPISpectraSpectraDataType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.PeptideHypothesisType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.SampleType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.SearchDatabaseType;
import org.proteored.miapeapi.xml.mzidentml.util.MzidentmlControlVocabularyXmlFactory;
import org.proteored.miapeapi.xml.mzidentml.util.Utils;
import org.proteored.miapeapi.xml.util.MiapeXmlUtil;
import org.proteored.miapeapi.xml.util.parallel.MapSync;

import pi.ParIterator;
import pi.ParIterator.Schedule;
import pi.ParIteratorFactory;
import pi.reductions.Reducible;
import pi.reductions.Reduction;

public class MiapeMSIDocumentImpl implements MiapeMSIDocument {
	private int msDocumentID;
	private static final int MAX_NUMBER_PARALLEL_PROCESSES = 6;

	private static Logger log = Logger.getLogger("log4j.logger.org.proteored");
	protected XmlMiapeFactory<MiapeMSDocument> xmlFactory;
	private final PSIPIMainMzIdentMLType mzIdentML;

	private PersistenceManager dbManager;
	private final User user;
	private final String projectName;
	private int id = -1;
	protected Contact contact;
	protected ControlVocabularyManager cvManager;
	private final List<FuGECommonAuditContactType> mzIdentContactList;
	private final List<PSIPIAnalysisSearchSpectrumIdentificationType> spectrumIdentifications;

	private final Set<IdentifiedProteinSet> proteinSets = new HashSet<IdentifiedProteinSet>();
	private final Set<InputParameter> inputParameters = new HashSet<InputParameter>();
	private final Set<Software> msiSoftwares = new HashSet<Software>();
	private final Set<InputDataSet> inputDataSets = new HashSet<InputDataSet>();
	private final Set<Validation> validations = new HashSet<Validation>();
	private final List<IdentifiedPeptide> peptides = new ArrayList<IdentifiedPeptide>();
	public String url;
	private String generatedFileURI;
	private final String mzIdentMLFileName;
	// Map<ProteinACC, Protein>
	private final Map<String, IdentifiedProtein> proteinHash = new HashMap<String, IdentifiedProtein>();

	public MiapeMSIDocumentImpl(PSIPIMainMzIdentMLType mzIdentML,
			ControlVocabularyManager cvManager, String mzIdentMLFileName,
			String projectName, boolean processInParallel) {
		this.mzIdentML = mzIdentML;
		mzIdentContactList = createContactList();
		user = null;
		spectrumIdentifications = createSpectrumIdentifications();
		this.cvManager = cvManager;
		this.projectName = projectName;
		this.mzIdentMLFileName = mzIdentMLFileName;
		if (processInParallel) {
			log.info("Starting processing of mzIdentML in parallel");
			processMzIdentMLInParallel();
		} else {
			log.info("Starting processing of mzIdentML using just one core");
			processMzIdentML();
		}
	}

	public MiapeMSIDocumentImpl(PSIPIMainMzIdentMLType mzIdentML,
			PersistenceManager databaseManager,
			ControlVocabularyManager cvManager, String user, String password,
			String mzIdentMLFileName, String projectName,
			boolean processInParallel) throws MiapeDatabaseException,
			MiapeSecurityException {
		this.mzIdentML = mzIdentML;
		mzIdentContactList = createContactList();
		this.user = databaseManager.getUser(user, password);
		spectrumIdentifications = createSpectrumIdentifications();
		this.cvManager = cvManager;
		this.projectName = projectName;
		dbManager = databaseManager;
		this.mzIdentMLFileName = mzIdentMLFileName;
		if (processInParallel) {
			log.info("Starting processing of mzIdentML in parallel");
			processMzIdentMLInParallel();
		} else {
			log.info("Starting processing of mzIdentML using just one core");
			processMzIdentML();
		}
	}

	/**
	 * Main method that reads the mzIdentML file and create the MIAPE MSI
	 * sections in parallel
	 * 
	 * @param mzIdentMLUnmarshaller
	 */
	private void processMzIdentMLInParallel() {
		Map<String, InputDataSet> inputDataSetMap = new HashMap<String, InputDataSet>();

		String spectrumIdentificationSoftwareID = "";
		// Main loop over SpectrumIdentifications elements
		for (PSIPIAnalysisSearchSpectrumIdentificationType spectrumIdent : mzIdentML
				.getAnalysisCollection().getSpectrumIdentification()) {
			Map<String, IdentifiedProtein> proteinHash = new HashMap<String, IdentifiedProtein>();

			log.info("Processing SI: " + spectrumIdent.getId());
			PSIPIAnalysisSearchSpectrumIdentificationProtocolType spectrumIdentProtocol = getSpectrumIdentificationProtocol(
					spectrumIdent.getSpectrumIdentificationProtocolRef(),
					mzIdentML.getAnalysisProtocolCollection()
							.getSpectrumIdentificationProtocol());

			PSIPIAnalysisProcessProteinDetectionProtocolType proteinDetectionProtocol = getProteinDetectionProtocol(spectrumIdent
					.getSpectrumIdentificationListRef());

			List<PSIPIAnalysisSearchSearchDatabaseType> databaseListXML = getSearchDatabases(
					spectrumIdent.getSearchDatabase(), mzIdentML
							.getDataCollection().getInputs()
							.getSearchDatabase());

			// MSI Software
			PSIPIAnalysisSearchAnalysisSoftwareType softwareXML = getSoftware(
					spectrumIdentProtocol.getAnalysisSoftwareRef(), mzIdentML
							.getAnalysisSoftwareList().getAnalysisSoftware());
			spectrumIdentificationSoftwareID = softwareXML.getId();
			Integer softwareID = MiapeXmlUtil.SoftwareCounter.increaseCounter();
			Software msiSoftware = new SoftwareImpl(softwareXML, mzIdentML
					.getAuditCollection().getContactGroup(), softwareID,
					cvManager);
			msiSoftwares.add(msiSoftware);

			PSIPIAnalysisSearchSpectrumIdentificationListType spectIdentListXML = getSpectrumIdentificationList(
					spectrumIdent.getSpectrumIdentificationListRef(), mzIdentML
							.getDataCollection().getAnalysisData()
							.getSpectrumIdentificationList());
			Long numSeqSearched = (long) -1;
			if (spectIdentListXML != null)
				numSeqSearched = spectIdentListXML.getNumSequencesSearched();

			// Input parameter and databases
			Integer inputParamID = MiapeXmlUtil.ParameterCounter
					.increaseCounter();
			InputParameter inputParameter = new InputParameterImpl(
					spectrumIdentProtocol, proteinDetectionProtocol,
					databaseListXML, msiSoftware, inputParamID, numSeqSearched,
					cvManager);
			inputParameters.add(inputParameter);

			// inputDataSet
			final List<InputSpectraType> inputSpectraXML = spectrumIdent
					.getInputSpectra();
			if (inputSpectraXML != null) {
				for (InputSpectraType inputSpectraType : inputSpectraXML) {
					final String spectraDataRef = inputSpectraType
							.getSpectraDataRef();
					if (!inputDataSetMap.containsKey(spectraDataRef)) {
						Integer inputDataSetID = MiapeXmlUtil.InputDataSetCounter
								.increaseCounter();
						InputDataSet inputDataSet = new InputDataSetImpl(
								inputDataSetID, spectraDataRef);
						inputDataSetMap.put(spectraDataRef, inputDataSet);
					}
				}
			}

			// proteinSet
			IdentifiedProteinSet proteinSet = new ProteinSetImpl(
					inputParameter, inputDataSets);
			proteinSets.add(proteinSet);

			List<PSIPIAnalysisSearchSpectrumIdentificationResultType> spectrumIdentificationResult = spectIdentListXML
					.getSpectrumIdentificationResult();

			int threadCount = SystemCoreManager
					.getAvailableNumSystemCores(MAX_NUMBER_PARALLEL_PROCESSES);
			final ParIterator<PSIPIAnalysisSearchSpectrumIdentificationResultType> iterator = ParIteratorFactory
					.createParIterator(spectrumIdentificationResult,
							threadCount, Schedule.GUIDED);
			log.info("Processing " + spectrumIdentificationResult.size()
					+ " SpectrumIdentificationResults using " + threadCount
					+ " cores");
			Reducible<List<IdentifiedPeptide>> reduciblePeptides = new Reducible<List<IdentifiedPeptide>>();
			Map<String, InputData> inputDataHash = new HashMap<String, InputData>();
			MapSync<String, InputData> syncInputDataHash = new MapSync<String, InputData>(
					inputDataHash);
			Reducible<Map<String, IdentifiedProtein>> reducibleProteinHash = new Reducible<Map<String, IdentifiedProtein>>();

			List<SpectrumIdentificationResultParallelProcesor> runners = new ArrayList<SpectrumIdentificationResultParallelProcesor>();
			for (int numCore = 0; numCore < threadCount; numCore++) {
				// take current DB session
				SpectrumIdentificationResultParallelProcesor runner = new SpectrumIdentificationResultParallelProcesor(
						iterator, numCore, cvManager, mzIdentML,
						syncInputDataHash, reduciblePeptides,
						reducibleProteinHash);
				runners.add(runner);
				runner.start();
			}

			// Main thread waits for worker threads to complete
			for (int k = 0; k < threadCount; k++) {
				try {
					runners.get(k).join();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			if (iterator.getAllExceptions().length > 0) {
				throw new IllegalArgumentException(
						iterator.getAllExceptions()[0].getException());
			}
			// Reductors
			Reduction<List<IdentifiedPeptide>> peptideListReduction = new Reduction<List<IdentifiedPeptide>>() {
				@Override
				public List<IdentifiedPeptide> reduce(
						List<IdentifiedPeptide> first,
						List<IdentifiedPeptide> second) {
					List<IdentifiedPeptide> peptides = new ArrayList<IdentifiedPeptide>();
					peptides.addAll(first);
					peptides.addAll(second);
					return peptides;
				}
			};

			Reduction<Map<String, IdentifiedProtein>> proteinHashReduction = new Reduction<Map<String, IdentifiedProtein>>() {
				@Override
				public Map<String, IdentifiedProtein> reduce(
						Map<String, IdentifiedProtein> first,
						Map<String, IdentifiedProtein> second) {
					Map<String, IdentifiedProtein> map = new HashMap<String, IdentifiedProtein>();

					List<Map<String, IdentifiedProtein>> listofmaps = new ArrayList<Map<String, IdentifiedProtein>>();
					listofmaps.add(first);
					listofmaps.add(second);
					for (Map<String, IdentifiedProtein> mapToReduce : listofmaps) {

						for (String proteinAcc : mapToReduce.keySet()) {
							if (!map.containsKey(proteinAcc)) {
								map.put(proteinAcc, mapToReduce.get(proteinAcc));
							} else {
								// Add peptides from protein2 to the protein1
								final IdentifiedProteinImpl protein = (IdentifiedProteinImpl) map
										.get(proteinAcc);
								final IdentifiedProtein protein2 = mapToReduce
										.get(proteinAcc);
								for (IdentifiedPeptide peptide2 : protein2
										.getIdentifiedPeptides()) {
									protein.addIdentifiedPeptide(peptide2);

									// delete protein2 from peptide
									IdentifiedPeptideImpl peptideImpl2 = (IdentifiedPeptideImpl) peptide2;
									final Iterator<IdentifiedProtein> iterator2 = peptideImpl2
											.getIdentifiedProteins().iterator();
									while (iterator2.hasNext()) {
										if (iterator2.next().getId() == protein2
												.getId())
											iterator2.remove();
									}
									// add protein1 to peptide
									peptideImpl2.addProtein(protein);
								}
							}
						}
					}
					return map;
				}
			};
			log.info("Collapsing thread results");
			peptides.addAll(reduciblePeptides.reduce(peptideListReduction));
			proteinHash = reducibleProteinHash.reduce(proteinHashReduction);

			for (String spectraDataRef : syncInputDataHash.keySet()) {
				if (inputDataSetMap.containsKey(spectraDataRef)) {
					final InputDataSet inputDataSet = inputDataSetMap
							.get(spectraDataRef);

					final Set<InputData> inputDatas = inputDataSet
							.getInputDatas();
					boolean include = true;
					for (InputData inputData : inputDatas) {
						if (inputData.getName().equals(spectraDataRef))
							include = false;
					}
					if (include)
						inputDatas.add(syncInputDataHash.get(spectraDataRef));
				}
			}

			// Add all the proteins to the proteinSet
			for (String protein_Acc : proteinHash.keySet()) {
				final IdentifiedProtein protein = proteinHash.get(protein_Acc);
				// if the protein has no peptide, do not report it -> this is
				// the case of having proteins with all peptides identified
				// containing passThreshold="false"
				if (protein.getIdentifiedPeptides() != null
						|| !protein.getIdentifiedPeptides().isEmpty()) {
					((ProteinSetImpl) proteinSet).addIdentifiedProtein(protein);
				}
			}
			log.info("Parsed " + proteinHash.size() + " proteins and "
					+ peptides.size() + " peptides.");
		}

		// add input data sets:
		for (InputDataSet inputDataSet : inputDataSetMap.values()) {
			inputDataSets.add(inputDataSet);
		}

		// for the protein detection protocol and the peptide identification
		// detection protocol
		HashMap<String, List<Object>> protocolsBySoftware = getProtocolsBySoftware(mzIdentML
				.getAnalysisProtocolCollection());
		if (protocolsBySoftware != null) {
			for (List<Object> list : protocolsBySoftware.values()) {
				// Validations
				validations.add(new ValidationImpl(list, mzIdentML
						.getAnalysisSoftwareList().getAnalysisSoftware(),
						mzIdentML.getAuditCollection().getContactGroup(),
						spectrumIdentificationSoftwareID, cvManager));
			}
		}

		// Add new validation softwares for the softwares not referenced by
		// protocols
		if (mzIdentML.getAnalysisSoftwareList() != null) {
			Set<String> referencesSoftwareRefs = getProtocolsBySoftwareIDs(mzIdentML
					.getAnalysisProtocolCollection());
			for (PSIPIAnalysisSearchAnalysisSoftwareType analysisSoftware : mzIdentML
					.getAnalysisSoftwareList().getAnalysisSoftware()) {
				String analysisSoftwareID = analysisSoftware.getId();
				if (!referencesSoftwareRefs.contains(analysisSoftwareID)
						&& !spectrumIdentificationSoftwareID
								.equals(analysisSoftwareID)) {
					validations.add(new ValidationImpl(analysisSoftware,
							mzIdentML.getAuditCollection().getContactGroup(),
							cvManager));
				}
			}
		}

		if (existsSourceFile()) {
			// Get the location of the first file in the list. The rest of them,
			// put it in GeneratedFilesDescription
			PSIPIAnalysisSearchSourceFileType file = mzIdentML
					.getDataCollection().getInputs().getSourceFile().get(0);
			generatedFileURI = file.getLocation();
		}

	}

	/**
	 * Main method that reads the mzIdentML file and create the MIAPE MSI
	 * sections
	 * 
	 * @param mzIdentMLUnmarshaller
	 */
	private void processMzIdentML() {
		String spectrumIdentificationSoftwareID = "";
		Map<String, InputDataSet> inputDataSetMap = new HashMap<String, InputDataSet>();
		// Main loop over SpectrumIdentifications elements
		for (PSIPIAnalysisSearchSpectrumIdentificationType spectrumIdent : mzIdentML
				.getAnalysisCollection().getSpectrumIdentification()) {

			PSIPIAnalysisSearchSpectrumIdentificationProtocolType spectrumIdentProtocol = getSpectrumIdentificationProtocol(
					spectrumIdent.getSpectrumIdentificationProtocolRef(),
					mzIdentML.getAnalysisProtocolCollection()
							.getSpectrumIdentificationProtocol());

			PSIPIAnalysisProcessProteinDetectionProtocolType proteinDetectionProtocol = getProteinDetectionProtocol(spectrumIdent
					.getSpectrumIdentificationListRef());

			List<PSIPIAnalysisSearchSearchDatabaseType> databaseListXML = getSearchDatabases(
					spectrumIdent.getSearchDatabase(), mzIdentML
							.getDataCollection().getInputs()
							.getSearchDatabase());

			// MSI Software
			PSIPIAnalysisSearchAnalysisSoftwareType softwareXML = getSoftware(
					spectrumIdentProtocol.getAnalysisSoftwareRef(), mzIdentML
							.getAnalysisSoftwareList().getAnalysisSoftware());
			spectrumIdentificationSoftwareID = softwareXML.getId();
			Integer softwareID = MiapeXmlUtil.SoftwareCounter.increaseCounter();
			Software msiSoftware = new SoftwareImpl(softwareXML, mzIdentML
					.getAuditCollection().getContactGroup(), softwareID,
					cvManager);
			msiSoftwares.add(msiSoftware);

			PSIPIAnalysisSearchSpectrumIdentificationListType spectIdentListXML = getSpectrumIdentificationList(
					spectrumIdent.getSpectrumIdentificationListRef(), mzIdentML
							.getDataCollection().getAnalysisData()
							.getSpectrumIdentificationList());
			Long numSeqSearched = (long) -1;
			if (spectIdentListXML != null)
				numSeqSearched = spectIdentListXML.getNumSequencesSearched();

			// Input parameter and databases
			Integer inputParamID = MiapeXmlUtil.ParameterCounter
					.increaseCounter();
			InputParameter inputParameter = new InputParameterImpl(
					spectrumIdentProtocol, proteinDetectionProtocol,
					databaseListXML, msiSoftware, inputParamID, numSeqSearched,
					cvManager);
			inputParameters.add(inputParameter);

			// inputDataSet
			final List<InputSpectraType> inputSpectra = spectrumIdent
					.getInputSpectra();
			if (inputSpectra != null) {
				for (InputSpectraType inputSpectraType : inputSpectra) {
					final String spectraDataRef = inputSpectraType
							.getSpectraDataRef();
					if (!inputDataSetMap.containsKey(spectraDataRef)) {
						Integer inputDataSetID = MiapeXmlUtil.InputDataSetCounter
								.increaseCounter();
						InputDataSet inputDataSet = new InputDataSetImpl(
								inputDataSetID, spectraDataRef);
						inputDataSetMap.put(spectraDataRef, inputDataSet);
					}
				}
			}
			// proteinSet
			IdentifiedProteinSet proteinSet = new ProteinSetImpl(
					inputParameter, inputDataSets);
			proteinSets.add(proteinSet);

			// Map<spectraDataXML.ID, InputData
			Map<String, InputData> inputDataHash = new HashMap<String, InputData>();

			List<PSIPIAnalysisSearchSpectrumIdentificationResultType> spectrumIdentificationResult = spectIdentListXML
					.getSpectrumIdentificationResult();

			log.info(spectrumIdentificationResult.size()
					+ " SpectrumIdentificationResults");
			int count = 1;
			long peptideCount = 0;
			for (PSIPIAnalysisSearchSpectrumIdentificationResultType spectIdentResultXML : spectrumIdentificationResult) {
				int percentage = count * 100
						/ spectrumIdentificationResult.size();
				log.debug("Processed " + percentage
						+ " % of the spectrum identification results.");
				count++;

				// TODO this is very important:!
				final String spectrumID = spectIdentResultXML.getSpectrumID();
				String spectrumRef = getSpectrumRef(spectrumID);

				// Retention time
				String RT = getRetentionTimeInSeconds(spectIdentResultXML);

				// Input data
				// check if the spectraData is already captured. If not, add a
				// new input Data
				PSIPISpectraSpectraDataType spectraDataXML = getSpectraData(
						spectIdentResultXML.getSpectraDataRef(), mzIdentML
								.getDataCollection().getInputs()
								.getSpectraData());

				if (!inputDataHash.containsKey(spectraDataXML.getId())) {
					Integer inputDataID = MiapeXmlUtil.InputDataCounter
							.increaseCounter();
					InputData inputData = new InputDataImpl(spectraDataXML,
							inputDataID);
					inputDataHash.put(spectraDataXML.getId(), inputData);
				}
				InputData inputData = inputDataHash.get(spectraDataXML.getId());

				// log.info(spectIdentResultXML.getSpectrumIdentificationItem().size()
				// + " SpectrumIdentificationItems");
				Set<PeptideScore> scoresFromFirstPeptide = new HashSet<PeptideScore>();

				List<PSIPIAnalysisSearchSpectrumIdentificationItemType> spectrumIdentificationItems = spectIdentResultXML
						.getSpectrumIdentificationItem();
				for (PSIPIAnalysisSearchSpectrumIdentificationItemType spectIdentItemXML : spectrumIdentificationItems) {

					// some peptides contribute to proteins even if they
					// have
					// not passed the threshold
					// if (spectIdentItemXML.isPassThreshold()) {

					PSIPIPolypeptidePeptideType peptideXML = getPeptide(
							spectIdentItemXML.getPeptideRef(), mzIdentML
									.getSequenceCollection().getPeptide());

					boolean includePeptide = false;
					final Set<PeptideScore> scores = IdentifiedPeptideImpl
							.getScoresFromThisPeptides(spectIdentItemXML,
									peptideXML, cvManager);
					if (scores == null || scores.isEmpty()) {
						log.info("Skipping SII:" + spectIdentItemXML.getId()
								+ " because no scores have found");
						continue;
					}
					if (spectIdentItemXML.getRank() == 1) {
						includePeptide = true;
						scoresFromFirstPeptide.clear();
						scoresFromFirstPeptide.addAll(scores);
					} else {
						// if the rank > 1 has the same scores, also
						// include it
						if (comparePeptideScores(scoresFromFirstPeptide, scores) == 0) {
							includePeptide = true;
							log.debug("Peptide with rank "
									+ spectIdentItemXML.getRank()
									+ " is going to be included");
						}
					}
					if (!includePeptide) {
						break;
					} else {
						// CREATE Peptide
						Integer peptideID = MiapeXmlUtil.PeptideCounter
								.increaseCounter();
						IdentifiedPeptide peptide = new IdentifiedPeptideImpl(
								spectIdentItemXML, peptideXML, mzIdentML,
								inputData, spectrumRef, peptideID, cvManager,
								proteinHash, RT);
						// if the peptide has no scores, not report it
						if (peptide.getScores() == null
								|| peptide.getScores().isEmpty())
							throw new IllegalMiapeArgumentException(
									"The peptide from SII:"
											+ spectIdentItemXML.getId()
											+ " has no scores!");

						// Add the peptide to the peptide list
						peptides.add(peptide);
						peptideCount++;

					}
				}
			}

			for (String spectraDataRef : inputDataHash.keySet()) {
				if (inputDataSetMap.containsKey(spectraDataRef)) {
					final InputDataSet inputDataSet = inputDataSetMap
							.get(spectraDataRef);
					boolean include = true;
					final InputData inputData = inputDataHash
							.get(spectraDataRef);
					for (InputData intpuData2 : inputDataSet.getInputDatas()) {
						if (intpuData2.getName().equals(inputData.getName())) {
							include = false;
							break;
						}
					}
					if (include)
						inputDataSet.getInputDatas().add(inputData);
				}
			}

			int numProteinsAdded = 0;
			// Add all the proteins to the proteinSet
			for (String protein_Acc : proteinHash.keySet()) {
				final IdentifiedProtein protein = proteinHash.get(protein_Acc);
				// if the protein has no peptide, do not report it -> this is
				// the case of having proteins with all peptides identified
				// containing passThreshold="false"
				if (protein.getIdentifiedPeptides() != null
						|| !protein.getIdentifiedPeptides().isEmpty()) {
					((ProteinSetImpl) proteinSet).addIdentifiedProtein(protein);
					numProteinsAdded++;
				}
			}
			log.info("Parsed " + numProteinsAdded + " proteins and "
					+ peptideCount + " peptides.");
		}

		for (InputDataSet insputDataSet : inputDataSetMap.values()) {
			inputDataSets.add(insputDataSet);
		}

		// for the protein detection protocol and the peptide identification
		// detection protocol
		HashMap<String, List<Object>> protocolsBySoftware = getProtocolsBySoftware(mzIdentML
				.getAnalysisProtocolCollection());
		if (protocolsBySoftware != null) {
			for (List<Object> list : protocolsBySoftware.values()) {
				// Validations
				validations.add(new ValidationImpl(list, mzIdentML
						.getAnalysisSoftwareList().getAnalysisSoftware(),
						mzIdentML.getAuditCollection().getContactGroup(),
						spectrumIdentificationSoftwareID, cvManager));
			}
		}

		// Add new validation softwares for the softwares not referenced by
		// protocols
		if (mzIdentML.getAnalysisSoftwareList() != null) {
			Set<String> referencesSoftwareRefs = getProtocolsBySoftwareIDs(mzIdentML
					.getAnalysisProtocolCollection());
			for (PSIPIAnalysisSearchAnalysisSoftwareType analysisSoftware : mzIdentML
					.getAnalysisSoftwareList().getAnalysisSoftware()) {
				String analysisSoftwareID = analysisSoftware.getId();
				if (!referencesSoftwareRefs.contains(analysisSoftwareID)
						&& !spectrumIdentificationSoftwareID
								.equals(analysisSoftwareID)) {
					validations.add(new ValidationImpl(analysisSoftware,
							mzIdentML.getAuditCollection().getContactGroup(),
							cvManager));
				}
			}
		}

		if (existsSourceFile()) {
			// Get the location of the first file in the list. The rest of them,
			// put it in GeneratedFilesDescription
			PSIPIAnalysisSearchSourceFileType file = mzIdentML
					.getDataCollection().getInputs().getSourceFile().get(0);
			generatedFileURI = file.getLocation();
		}

	}

	private String getRetentionTimeInSeconds(
			PSIPIAnalysisSearchSpectrumIdentificationResultType spectIdentResultXML) {
		if (spectIdentResultXML != null) {
			if (spectIdentResultXML.getParamGroup() != null) {
				for (FuGECommonOntologyParamType paramType : spectIdentResultXML
						.getParamGroup()) {
					if (paramType instanceof FuGECommonOntologyCvParamType) {
						FuGECommonOntologyCvParamType cvparam = (FuGECommonOntologyCvParamType) paramType;
						ControlVocabularyTerm cvTerm = RetentionTime
								.getInstance(cvManager).getCVTermByAccession(
										new Accession(cvparam.getAccession()));
						if (cvTerm != null) {
							if (cvparam.getValue() != null) {
								try {
									int num = Integer.valueOf(cvparam
											.getValue());
									// check unit
									String unitAccession = cvparam
											.getUnitAccession();
									if (unitAccession != null) {
										if ("UO:0000010".equals(unitAccession)) {
											log.debug("Retention time in seconds: "
													+ num);
										} else if ("UO:0000031"
												.equals(unitAccession)) {
											log.debug("Retention time in minutes: "
													+ num);
											num = num * 60;
											log.debug("Retention time converted to seconds: "
													+ num);
										}
									}
									return String.valueOf(num);
								} catch (NumberFormatException e) {

								}
							}
						}
					}
				}
			}
		}
		return null;
	}

	private HashMap<String, List<Object>> getProtocolsBySoftware(
			AnalysisProtocolCollectionType analysisProtocolCollection) {
		HashMap<String, List<Object>> ret = new HashMap<String, List<Object>>();
		if (analysisProtocolCollection != null) {
			final List<PSIPIAnalysisSearchSpectrumIdentificationProtocolType> spectrumIdentificationProtocol = analysisProtocolCollection
					.getSpectrumIdentificationProtocol();
			if (spectrumIdentificationProtocol != null) {
				for (PSIPIAnalysisSearchSpectrumIdentificationProtocolType sip : spectrumIdentificationProtocol) {
					final String analysisSoftwareRef = sip
							.getAnalysisSoftwareRef();
					if (ret.containsKey(analysisSoftwareRef))
						ret.get(analysisSoftwareRef).add(sip);
					else {
						List<Object> list = new ArrayList<Object>();
						list.add(sip);
						ret.put(analysisSoftwareRef, list);
					}
				}
			}
			final PSIPIAnalysisProcessProteinDetectionProtocolType proteinDetectionProtocol = analysisProtocolCollection
					.getProteinDetectionProtocol();
			if (proteinDetectionProtocol != null) {
				final String analysisSoftwareRef = proteinDetectionProtocol
						.getAnalysisSoftwareRef();
				if (ret.containsKey(analysisSoftwareRef))
					ret.get(analysisSoftwareRef).add(proteinDetectionProtocol);
				else {
					List<Object> list = new ArrayList<Object>();
					list.add(proteinDetectionProtocol);
					ret.put(analysisSoftwareRef, list);
				}
			}
			return ret;
		}
		return null;
	}

	private Set<String> getProtocolsBySoftwareIDs(
			AnalysisProtocolCollectionType analysisProtocolCollection2) {
		HashSet<String> ret = new HashSet<String>();
		if (analysisProtocolCollection2 != null) {
			final List<PSIPIAnalysisSearchSpectrumIdentificationProtocolType> spectrumIdentificationProtocol = analysisProtocolCollection2
					.getSpectrumIdentificationProtocol();
			if (spectrumIdentificationProtocol != null) {
				for (PSIPIAnalysisSearchSpectrumIdentificationProtocolType sip : spectrumIdentificationProtocol) {
					final String analysisSoftwareRef = sip
							.getAnalysisSoftwareRef();

					ret.add(analysisSoftwareRef);
				}
			}
			final PSIPIAnalysisProcessProteinDetectionProtocolType proteinDetectionProtocol = analysisProtocolCollection2
					.getProteinDetectionProtocol();
			if (proteinDetectionProtocol != null) {
				final String analysisSoftwareRef = proteinDetectionProtocol
						.getAnalysisSoftwareRef();
				ret.add(analysisSoftwareRef);
			}
			return ret;
		}
		return null;
	}

	private PSIPIAnalysisProcessProteinDetectionProtocolType getProteinDetectionProtocol(
			String spectrumIdentificationListRef) {
		final PSIPIAnalysisProcessProteinDetectionType pd = mzIdentML
				.getAnalysisCollection().getProteinDetection();
		if (pd != null && pd.getInputSpectrumIdentifications() != null) {
			for (InputSpectrumIdentificationsType isi : pd
					.getInputSpectrumIdentifications()) {
				if (isi.getSpectrumIdentificationListRef().equals(
						spectrumIdentificationListRef)) {
					final String proteinDetectionProtocolRef = pd
							.getProteinDetectionProtocolRef();
					final PSIPIAnalysisProcessProteinDetectionProtocolType proteinDetectionProtocol = mzIdentML
							.getAnalysisProtocolCollection()
							.getProteinDetectionProtocol();
					if (proteinDetectionProtocol != null) {
						if (proteinDetectionProtocol.getId().equals(
								proteinDetectionProtocolRef))
							return proteinDetectionProtocol;
					}
				}
			}
		}
		return null;
	}

	/**
	 * Returns the spectrumRef of the spectrumIdentificationResult
	 * 
	 * @param spectrumID
	 *            : If the mzIdentML comes from a MASCOT mgf search, the
	 *            spectrumID should be "index=x" where x is the order of the
	 *            spectra in the MGF (starting by 0) If the mzIdentML comes from
	 *            a MASCCOT mzML search, the spectrumID should be
	 *            "mzMLid=controllerType=0 controllerNumber=1 scan=3423" where
	 *            the scan is the order of the spectra in the mzML (starting by
	 *            1)
	 * @return
	 */
	private String getSpectrumRef(String spectrumID) {
		if (spectrumID == null)
			return null;

		String mzMLSpectrumIDRegexp = "^mzMLid=(.*)$";

		if (Pattern.matches(mzMLSpectrumIDRegexp, spectrumID)) {
			// in case of being a spectrumID of a mzML file, return the
			// string that appears after the "mzMLid="
			Pattern p = Pattern.compile(mzMLSpectrumIDRegexp);
			Matcher m = p.matcher(spectrumID);
			if (m.find())
				return m.group(1);

		}
		Integer specRefInt = 0;
		String mgfSpectrumIDRegexp = "^index=(\\d+)$";
		String mzMLSpectrumIDRegexp2 = ".*scan=(\\d+)$";
		String mgfSpectrumIDRegexpQuery = "^query=(\\d+)$";
		String mgfSpectrumIDRegexpQuery2 = "^(\\d+)$";

		// if is like "index=1235"
		if (Pattern.matches(mgfSpectrumIDRegexp, spectrumID)) {
			Pattern p = Pattern.compile(mgfSpectrumIDRegexp);
			Matcher m = p.matcher(spectrumID);
			if (m.find()) {
				specRefInt = Integer.valueOf(m.group(1)) + 1; // sum 1 (starts
																// by 0)
			}
			// if it is like
			// "mzMLid=controllerType=0 controllerNumber=1 scan=3423"
		} else if (Pattern.matches(mzMLSpectrumIDRegexp2, spectrumID)) {
			Pattern p = Pattern.compile(mzMLSpectrumIDRegexp2);
			Matcher m = p.matcher(spectrumID);
			if (m.find()) {
				specRefInt = Integer.valueOf(m.group(1)); // don't sum 1 (starts
															// by 1)
			}
		} else if (Pattern.matches(mgfSpectrumIDRegexpQuery, spectrumID)) {
			Pattern p = Pattern.compile(mgfSpectrumIDRegexpQuery);
			Matcher m = p.matcher(spectrumID);
			if (m.find()) {
				specRefInt = Integer.valueOf(m.group(1));
			}
		} else if (Pattern.matches(mgfSpectrumIDRegexpQuery2, spectrumID)) {
			Pattern p = Pattern.compile(mgfSpectrumIDRegexpQuery2);
			Matcher m = p.matcher(spectrumID);
			if (m.find()) {
				specRefInt = Integer.valueOf(m.group(1));
			}
		}
		if (specRefInt != 0)
			return specRefInt.toString();
		return null;
	}

	protected static PSIPIAnalysisProcessProteinDetectionHypothesisType getProteinHypothesisByPeptideEvidenceOrByDBSequence(
			String peptideEvidenceId, String dbSequenceRef,
			PSIPIMainMzIdentMLType mzIdentML) {

		final DataCollectionType dataCollection = mzIdentML.getDataCollection();
		if (dataCollection != null) {
			final AnalysisDataType analysisData = dataCollection
					.getAnalysisData();
			if (analysisData != null) {
				final PSIPIAnalysisProcessProteinDetectionListType proteinDetectionList = analysisData
						.getProteinDetectionList();
				if (proteinDetectionList != null) {
					final List<PSIPIAnalysisProcessProteinAmbiguityGroupType> proteinAmbiguityGroup = proteinDetectionList
							.getProteinAmbiguityGroup();
					if (proteinAmbiguityGroup != null
							&& !proteinAmbiguityGroup.isEmpty()) {
						for (PSIPIAnalysisProcessProteinAmbiguityGroupType proteinAmbGroupXML : proteinAmbiguityGroup) {
							final List<PSIPIAnalysisProcessProteinDetectionHypothesisType> proteinDetectionHypothesis = proteinAmbGroupXML
									.getProteinDetectionHypothesis();
							if (proteinDetectionHypothesis != null) {
								for (PSIPIAnalysisProcessProteinDetectionHypothesisType proteinHypothesisXML : proteinDetectionHypothesis) {
									// // DBSequence is optional
									// if
									// (proteinHypothesisXML.getDBSequenceRef()
									// != null) {
									// if
									// (proteinHypothesisXML.getDBSequenceRef().equals(
									// dbSequenceRef)) {
									// return proteinHypothesisXML;
									// }
									// } else {
									// if DBSequence is not present
									for (PeptideHypothesisType peptideHypothesisXML : proteinHypothesisXML
											.getPeptideHypothesis()) {
										if (peptideEvidenceId
												.equals(peptideHypothesisXML
														.getPeptideEvidenceRef())) {
											return proteinHypothesisXML;
										}
									}
									// }

								}
							} else {
								return null;
							}
						}
					}
				}
			}
		}
		return null;
	}

	protected static PSIPIAnalysisSearchDBSequenceType getDBSequence(
			String dbSequenceRef,
			List<PSIPIAnalysisSearchDBSequenceType> dbSequences) {
		for (PSIPIAnalysisSearchDBSequenceType dbSequenceXML : dbSequences) {
			if (dbSequenceXML.getId().equals(dbSequenceRef)) {
				return dbSequenceXML;
			}
		}
		return null;
	}

	private PSIPIPolypeptidePeptideType getPeptide(String peptideRef,
			List<PSIPIPolypeptidePeptideType> peptides) {
		for (PSIPIPolypeptidePeptideType polypeptideXML : peptides) {
			if (polypeptideXML.getId().equals(peptideRef)) {
				return polypeptideXML;
			}
		}
		return null;
	}

	private PSIPISpectraSpectraDataType getSpectraData(String spectraDataRef,
			List<PSIPISpectraSpectraDataType> spectraDatas) {
		for (PSIPISpectraSpectraDataType spectraData : spectraDatas) {
			if (spectraData.getId().equals(spectraDataRef)) {
				return spectraData;
			}
		}
		return null;
	}

	private PSIPIAnalysisSearchSpectrumIdentificationListType getSpectrumIdentificationList(
			String spectrumIdentificationListRef,
			List<PSIPIAnalysisSearchSpectrumIdentificationListType> spectrumIdentificationLists) {
		if (spectrumIdentificationLists != null) {
			for (PSIPIAnalysisSearchSpectrumIdentificationListType spectIdentList : spectrumIdentificationLists) {
				if (spectIdentList.getId()
						.equals(spectrumIdentificationListRef)) {
					return spectIdentList;
				}
			}
		}
		return null;
	}

	private PSIPIAnalysisSearchAnalysisSoftwareType getSoftware(
			String analysisSoftwareRef,
			List<PSIPIAnalysisSearchAnalysisSoftwareType> softwareListXML) {
		for (PSIPIAnalysisSearchAnalysisSoftwareType softwareXML : softwareListXML) {
			if (softwareXML.getId().equals(analysisSoftwareRef)) {
				return softwareXML;
			}
		}
		return null;
	}

	/**
	 * Get a List of PSIPIAnalysisSearchSearchDatabaseType from an input list
	 * looking for the references in searchDatabaseRefList
	 * 
	 * @param searchDatabaseRefList
	 *            list of references
	 * @param list
	 *            input list
	 * @return
	 */
	private List<PSIPIAnalysisSearchSearchDatabaseType> getSearchDatabases(
			List<SearchDatabaseType> searchDatabaseRefList,
			List<PSIPIAnalysisSearchSearchDatabaseType> list) {
		List<PSIPIAnalysisSearchSearchDatabaseType> ret = new ArrayList<PSIPIAnalysisSearchSearchDatabaseType>();

		for (SearchDatabaseType searchDatabaseRef : searchDatabaseRefList) {
			for (PSIPIAnalysisSearchSearchDatabaseType database : list) {
				if (searchDatabaseRef.getSearchDatabaseRef().equals(
						database.getId())) {
					ret.add(database);
				}
			}
		}
		return ret;
	}

	private PSIPIAnalysisSearchSpectrumIdentificationProtocolType getSpectrumIdentificationProtocol(
			String id,
			List<PSIPIAnalysisSearchSpectrumIdentificationProtocolType> list) {
		for (PSIPIAnalysisSearchSpectrumIdentificationProtocolType specIdentProtocol : list) {
			if (specIdentProtocol.getId().equals(id))
				return specIdentProtocol;
		}
		return null;
	}

	private List<PSIPIAnalysisSearchSpectrumIdentificationType> createSpectrumIdentifications() {
		if (mzIdentML.getAnalysisCollection() != null
				&& mzIdentML.getAnalysisCollection()
						.getSpectrumIdentification() != null) {
			return mzIdentML.getAnalysisCollection()
					.getSpectrumIdentification();
		}
		return Collections.emptyList();
	}

	public void setDatabaseManager(PersistenceManager dbManager) {
		this.dbManager = dbManager;
	}

	@Override
	public String getGeneratedFilesDescription() {
		StringBuilder sb = new StringBuilder();
		if (existsSourceFile() == false) {
			return null;
		}
		int counter = 1;
		for (PSIPIAnalysisSearchSourceFileType file : mzIdentML
				.getDataCollection().getInputs().getSourceFile()) {
			if (file.getName() != null) {
				sb.append(Utils.SOURCE_FILE_NAME + "=" + file.getName());
				sb.append(MiapeXmlUtil.TERM_SEPARATOR);
			}
			if (file.getLocation() != null) {
				sb.append(Utils.LOCATION + "=" + file.getLocation());
				sb.append(MiapeXmlUtil.TERM_SEPARATOR);
			}
			if (file.getExternalFormatDocumentation() != null) {
				sb.append(Utils.EXTERNAL_FORMAT_DOCUMENTATION + "="
						+ file.getExternalFormatDocumentation());
				sb.append(MiapeXmlUtil.TERM_SEPARATOR);
			}
			if (file.getFileFormat() != null) {
				FileFormat fileFormat = file.getFileFormat();
				fileFormat.getCvParam();
				sb.append(Utils.FILE_FORMAT + "=");
				sb.append(MzidentmlControlVocabularyXmlFactory
						.readEntireParam(fileFormat.getCvParam()));
				sb.append(MiapeXmlUtil.TERM_SEPARATOR);
			}
			List<FuGECommonOntologyParamType> paramGroup = file.getParamGroup();
			for (FuGECommonOntologyParamType param : paramGroup) {
				MzidentmlControlVocabularyXmlFactory.readEntireParam(param);
				sb.append(MiapeXmlUtil.TERM_SEPARATOR);
			}

			if (counter < mzIdentML.getDataCollection().getInputs()
					.getSourceFile().size()) {
				sb.append(MiapeXmlUtil.TERM_SEPARATOR);
			}
			counter++;
		}
		if (sb.length() > 1000)
			return sb.substring(0, 1000);
		return sb.toString();
	}

	@Override
	public String getGeneratedFilesURI() {
		return generatedFileURI;

	}

	@Override
	public Set<IdentifiedProteinSet> getIdentifiedProteinSets() {

		/*
		 * List<IdentifiedProtein> proteins = new
		 * ArrayList<IdentifiedProtein>(); Map<String,
		 * PSIPIAnalysisSearchDBSequenceType> mapProteins =
		 * initMapProteins(mzIdentML.getSequenceCollection().getDBSequence());
		 * Map<String, PSIPIPolypeptidePeptideType> mapPeptides =
		 * initMapPeptides(mzIdentML.getSequenceCollection().getPeptide());
		 * Map<String, PSIPIAnalysisSearchSpectrumIdentificationItemType>
		 * mapEvidenceSpectrum = new HashMap<String,
		 * PSIPIAnalysisSearchSpectrumIdentificationItemType>(); Map<String,
		 * PSIPIAnalysisSearchDBSequenceType> mapEvidenceProtein = new
		 * HashMap<String, PSIPIAnalysisSearchDBSequenceType>();
		 * Map<PSIPIPolypeptidePeptideType,
		 * PSIPIAnalysisSearchSpectrumIdentificationItemType>
		 * mapPeptidesSpectrum = new HashMap<PSIPIPolypeptidePeptideType,
		 * PSIPIAnalysisSearchSpectrumIdentificationItemType>();
		 * initPepEvidenceMap(mapPeptides, mapEvidenceSpectrum,
		 * mapPeptidesSpectrum, mapEvidenceProtein, mapProteins); if
		 * (hasIdentifiedProteins()) {
		 * PSIPIAnalysisProcessProteinDetectionListType proteinDetectionList =
		 * mzIdentML
		 * .getDataCollection().getAnalysisData().getProteinDetectionList(); if
		 * (proteinDetectionList != null) {
		 * List<PSIPIAnalysisProcessProteinAmbiguityGroupType> proteinGroups =
		 * proteinDetectionList.getProteinAmbiguityGroup(); for
		 * (PSIPIAnalysisProcessProteinAmbiguityGroupType proteinGroup :
		 * proteinGroups) { for
		 * (PSIPIAnalysisProcessProteinDetectionHypothesisType hypothesis :
		 * proteinGroup.getProteinDetectionHypothesis()) { if
		 * (hypothesis.isPassThreshold()) { // This has been an advise from Andy
		 * Jones: it is better to do it, than only to include the highest score.
		 * proteins.add(new IdentifiedProteinImpl(hypothesis ,
		 * mapEvidenceSpectrum, mapEvidenceProtein , proteinDetectionList
		 * ,mapPeptides, mapProteins)); } } } } else { for
		 * (PSIPIAnalysisSearchDBSequenceType xmlProtein :
		 * mzIdentML.getSequenceCollection().getDBSequence()) { proteins.add(new
		 * IdentifiedProteinImpl(xmlProtein, mapPeptides, mapEvidenceSpectrum,
		 * mapEvidenceProtein)); } } } else { IdentifiedProtein protein =
		 * ProteinType.UNIDENTIFIED.createUnidentifiedProtein(); for
		 * (Entry<PSIPIPolypeptidePeptideType,
		 * PSIPIAnalysisSearchSpectrumIdentificationItemType> pepSpectrum :
		 * mapPeptidesSpectrum.entrySet()) {
		 * protein.getIdentifiedPeptides().add(new
		 * IdentifiedPeptideImpl(pepSpectrum.getValue(), pepSpectrum.getKey()));
		 * } proteins.add(protein); } return proteins;
		 */
		return proteinSets;
	}

	@Override
	public Set<InputParameter> getInputParameters() {
		return inputParameters;
	}

	@Override
	public Set<Software> getSoftwares() {
		return msiSoftwares;
	}

	@Override
	public int getMSDocumentReference() {

		return msDocumentID;
	}

	@Override
	public Set<Validation> getValidations() {

		return validations;
	}

	@Override
	public MSContact getContact() {
		if (mzIdentML.getProvider() != null) {
			if (mzIdentML != null) {
				return new ContactImpl(mzIdentML, mzIdentContactList, user);
			}
		}
		return null;
	}

	@Override
	public MiapeDate getDate() {
		if (mzIdentML.getCreationDate() != null)
			return new MiapeDate(mzIdentML.getCreationDate().toString());
		return new MiapeDate(new Date(System.currentTimeMillis()));
	}

	@Override
	public int getId() {
		return id;
	}

	@Override
	public Date getModificationDate() {
		return new Date(System.currentTimeMillis());
	}

	@Override
	public String getName() {
		if (mzIdentMLFileName != null)
			return "MIAPE MSI from '" + mzIdentMLFileName + "'";
		return "MIAPE MSI from mzIdentML file";
	}

	@Override
	public User getOwner() {
		return user;
	}

	@Override
	public Project getProject() {
		if (id > 0 && dbManager != null) {
			try {
				return dbManager
						.getMiapeMSIPersistenceManager()
						.getMiapeById(id, user.getUserName(),
								user.getPassword()).getProject();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return new ProjectImpl(projectName, user, dbManager);
	}

	@Override
	public Boolean getTemplate() {
		return Boolean.FALSE;
	}

	@Override
	public String getVersion() {
		return "1.0";
	}

	@Override
	public void delete(String userName, String password)
			throws MiapeDatabaseException, MiapeSecurityException {
		if (dbManager == null)
			throw new MiapeDatabaseException(
					"The persistance method is not defined.");
		if (id > 0) {
			dbManager.getMiapeMSIPersistenceManager().deleteById(id, userName,
					password);
		} else
			throw new MiapeDatabaseException("The MIAPE is not stored yet!");
	}

	@Override
	public int store() throws MiapeDatabaseException, MiapeSecurityException {
		if (dbManager == null)
			throw new MiapeDatabaseException(
					"The persistance method is not defined.");
		id = dbManager.getMiapeMSIPersistenceManager().store(this);
		return id;
	}

	@Override
	public MiapeXmlFile<MiapeMSIDocument> toXml() {
		return MiapeMSIXmlFactory.getFactory().toXml(this, cvManager);
	}

	private boolean existsSourceFile() {
		return existsDataCollection()
				&& existsInputs()
				&& mzIdentML.getDataCollection().getInputs().getSourceFile() != null;
	}

	private boolean existsInputs() {
		return mzIdentML.getDataCollection().getInputs() != null;
	}

	private boolean existsDataCollection() {
		return mzIdentML.getDataCollection() != null;
	}

	private List<FuGECommonAuditContactType> createContactList() {
		FuGECollectionAuditCollectionType auditCollection = mzIdentML
				.getAuditCollection();
		List<FuGECommonAuditContactType> contactGroup = auditCollection
				.getContactGroup();
		return contactGroup;
	}

	@Override
	public String toString() {
		return "MSIDocumentFromMzIndentML [" + " getContact()=" + getContact()
				+ ", getDate()=" + getDate()
				+ ", getGeneratedFilesDescription()="
				+ getGeneratedFilesDescription() + ", getGeneratedFilesUrl()="
				+ getGeneratedFilesURI() + ", getId()=" + getId()
				+ ", getIdentifiedProteinSets()=" + getIdentifiedProteinSets()
				+ ", getInputDataSets()=" + getInputDataSets()
				+ ", getInputParameters()=" + getInputParameters()
				+ ", getModificationDate()=" + getModificationDate()
				+ ", getMsiSoftwares()=" + getSoftwares() + ", getName()="
				+ getName() + ", getOwner()=" + getOwner() + ", getPrideUrl()="
				+ getAttachedFileLocation() + ", getProject()=" + getProject()
				+ ", getReferencedMSDocument()=" + getMSDocumentReference()
				+ ", getTemplate()=" + getTemplate() + ", getValidations()="
				+ getValidations() + ", getVersion()=" + getVersion() + "]";
	}

	@Override
	public Set<MSIAdditionalInformation> getAdditionalInformations() {
		Set<MSIAdditionalInformation> addInfos = new HashSet<MSIAdditionalInformation>();

		// Capture information about the samples
		if (mzIdentML.getAnalysisSampleCollection() != null) {
			for (SampleType sampleXML : mzIdentML.getAnalysisSampleCollection()
					.getSample()) {

				addInfos.add(new AdditionalInformationImpl(sampleXML));
			}
		}

		// Capture information from the biobliographic references
		if (mzIdentML.getBibliographicReference() != null) {
			if (mzIdentML.getBibliographicReference().size() > 0) {
				for (FuGECommonReferencesBibliographicReferenceType referenceXML : mzIdentML
						.getBibliographicReference()) {
					addInfos.add(new AdditionalInformationImpl(referenceXML));
				}
			}
		}

		if (addInfos.size() > 0)
			return addInfos;
		return null;
	}

	@Override
	public ValidationReport getValidationReport() {
		return MiapeMSIValidator.getInstance().getReport(this);
	}

	@Override
	public Set<InputDataSet> getInputDataSets() {
		return inputDataSets;
	}

	@Override
	public String getAttachedFileLocation() {
		return url;
	}

	public void setAttachedFileURL(String fileURL) {
		final File file = new File(fileURL);
		// convert to local url
		if (file.exists()) {
			try {
				fileURL = file.toURI().toURL().toString();
			} catch (MalformedURLException e) {
			}
		}
		url = fileURL;
		// also add it to the generated file
		setGeneratedFileURI(fileURL);

	}

	public void setGeneratedFileURI(String generatedFileURI) {
		this.generatedFileURI = generatedFileURI;

	}

	@Override
	public void setReferencedMSDocument(int msDocumentID) {
		this.msDocumentID = msDocumentID;
	}

	@Override
	public List<IdentifiedPeptide> getIdentifiedPeptides() {
		return peptides;
	}

	private int comparePeptideScores(Set<PeptideScore> scoresFromFirstPeptide,
			Set<PeptideScore> scores) {
		if (scoresFromFirstPeptide != null && scores != null) {
			if (scores.size() == scoresFromFirstPeptide.size()) {
				for (PeptideScore peptideScore : scores) {
					if (!foundPeptideScore(peptideScore, scoresFromFirstPeptide))
						return -1;
				}
				return 0;
			}
		}
		return -1;
	}

	private boolean foundPeptideScore(PeptideScore peptideScore,
			Set<PeptideScore> scoresFromFirstPeptide) {
		for (PeptideScore peptideScore2 : scoresFromFirstPeptide) {
			if (peptideScore2.getName().equals(peptideScore.getName()))
				if (peptideScore2.getValue().equals(peptideScore.getValue()))
					return true;
		}
		return false;
	}
}
